<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>地理围栏</title>
    <script src="https://api.map.baidu.com/api?v=3.0&ak=TnnvUz71nq8nInn6dsFjdKHQeQzMO7u2"></script>
    <script src="https://api.map.baidu.com/library/GeoUtils/1.2/src/GeoUtils_min.js"></script>
    <style>
      body,
      html {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
        font-family: Arial, sans-serif;
      }
      #map-container {
        width: 100%;
        height: 100%;
      }
      #control-panel {
        position: absolute;
        top: 10px;
        left: 10px;
        background: white;
        padding: 10px;
        border-radius: 5px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
        z-index: 10;
        display: flex;
        flex-direction: column;
        text-align: center;
        width: 20vw;
        max-width: 200px;
      }
      button {
        margin: 5px 0;
        padding: 5px 10px;
        cursor: pointer;
        border-radius: 10px;
        border: 1px solid #ccc;
        background-color: #f8f8f8;
        transition: all 0.3s;
      }
      button:hover {
        background-color: #e8e8e8;
      }
      .fence-item {
        padding: 8px;
        margin: 5px;
        background: #f0f0f0;
        border-radius: 4px;
        cursor: pointer;
      }
      .fence-item:hover {
        background: #e0e0e0;
      }
      .alarm {
        position: absolute;
        top: 10px;
        right: 10px;
        background: #ff4444;
        color: white;
        padding: 10px;
        border-radius: 5px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
        z-index: 10;
        display: none;
        animation: blink 1s infinite;
      }
      @keyframes blink {
        0%,
        50% {
          opacity: 1;
        }
        51%,
        100% {
          opacity: 0.7;
        }
      }
      .simulation-controls {
        margin-top: 10px;
        padding-top: 10px;
        border-top: 1px solid #eee;
      }
      .status-indicator {
        width: 10px;
        height: 10px;
        border-radius: 50%;
        display: inline-block;
        margin-right: 5px;
      }
      .status-ok {
        background-color: #4caf50;
      }
      .status-alarm {
        background-color: #f44336;
      }
    </style>
  </head>
  <body>
    <div id="map-container"></div>
    <!-- 控制面板 -->
    <div id="control-panel">
      <h3>围栏管理</h3>
      <button id="start-drawing">开始绘制</button>
      <button id="end-drawing">结束绘制</button>
      <button id="clear-fences">清除所有</button>

      <div class="simulation-controls">

        <div>
          <span class="status-indicator status-ok" id="status-indicator"></span>
          <span id="status-text">正常</span>
        </div>
      </div>
    </div>

    <!-- 报警提示 -->
    <div id="alarm" class="alarm">
      <strong>围栏报警!</strong>
      <div id="alarm-details"></div>
    </div>

    <script type="text/javascript">
      // 配置参数
      const config = {
        ak: 'TnnvUz71nq8nInn6dsFjdKHQeQzMO7u2', // 百度AK
        defaultCenter: new BMap.Point(117.302574, 31.849504), // 默认中心点(BD09坐标)
        zoom: 16, // 默认缩放级别
        debug: false, // 是否开启调试模式
        vehicleIconUrl:
          'https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-red.png',
        convertOptions: {
          from: 1, // WGS84坐标系
          to: 5, // BD09MC坐标系
        },
        simulation: {
          speed: 0.0005, // 模拟移动速度
          interval: 5000, // 模拟点间隔时间(ms)
        },
      }

      // DOM 缓存
      const $startDrawing = document.getElementById('start-drawing')
      const $endDrawing = document.getElementById('end-drawing')
      const $clearFences = document.getElementById('clear-fences')
      const $alarm = document.getElementById('alarm')
      const $alarmDetails = document.getElementById('alarm-details')
      const $startSimulation = document.getElementById('start-simulation')
      const $stopSimulation = document.getElementById('stop-simulation')
      const $statusIndicator = document.getElementById('status-indicator')
      const $statusText = document.getElementById('status-text')

      // 全局变量
      let map = null
      let messagePort = null
      let vehicleMarker = null
      let geoFences = []
      let isDrawing = false
      let currentFence = null
      let convertor = new BMap.Convertor() // 坐标转换器实例
      let simulationInterval = null
      let currentSimulationIndex = 0
      let isSimulating = false
      let alarmSound = new Audio(
        'https://assets.mixkit.co/active_storage/sfx/2869/2869-preview.mp3'
      )
      let currentVehiclePosition = null // 保存当前车辆位置

      // 初始化函数
      function init() {
        setupMessageListener()
        initMap()
        setupGeoFenceControls()
        setupSimulationControls()
      }

      // 初始化地图
      function initMap() {
        map = new BMap.Map('map-container')
        map.centerAndZoom(config.defaultCenter, config.zoom)
        map.enableScrollWheelZoom(true) // 明确启用滚轮缩放

        const navigationControl = new BMap.NavigationControl({
          type: BMAP_NAVIGATION_CONTROL_ZOOM,
          anchor: BMAP_ANCHOR_BOTTOM_RIGHT,
          offset: new BMap.Size(10, 50),
        })
        map.addControl(navigationControl)

        // 初始化车辆标记
        initVehicleMarker(config.defaultCenter)
      }

      // 初始化车辆标记
      function initVehicleMarker(point) {
        currentVehiclePosition = point // 保存当前位置

        if (!vehicleMarker) {
          const icon = new BMap.Icon(
            'https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-red.png',

            new BMap.Size(50, 58)
          )
          vehicleMarker = new BMap.Marker(point, { icon })
          map.addOverlay(vehicleMarker)
        } else {
          vehicleMarker.setPosition(point)
        }
        map.panTo(point)
      }

      // 坐标转换并更新车辆位置
      function updateVehiclePosition(lng, lat) {
        // 转换坐标系 (WGS84 -> BD09)
        convertor.translate(
          [new BMap.Point(lng, lat)],
          config.convertOptions.from,
          config.convertOptions.to,
          (result) => {
            if (
              result.status === 0 &&
              result.points &&
              result.points.length > 0
            ) {
              const convertedPoint = result.points[0]
              initVehicleMarker(convertedPoint)
              checkGeoFences(convertedPoint)
            } else {
              console.error('坐标转换失败:', result)
            }
          }
        )
      }

      // 设置地理围栏控制
      function setupGeoFenceControls() {
        // 开始绘制
        $startDrawing.addEventListener('click', () => {
          if (isDrawing) return
          isDrawing = true
          currentFence = {
            points: [],
            polygon: null,
            name: `围栏${geoFences.length + 1}`,
            id: Date.now(), // 使用时间戳作为临时ID
          }
          $startDrawing.style.backgroundColor = '#4CAF50'
          $startDrawing.style.color = 'white'
        })

        // 结束绘制
        $endDrawing.addEventListener('click', () => {
          if (!isDrawing || currentFence.points.length < 3) {
            cancelDrawing()
            return
          }
          finalizeFence()
          $startDrawing.style.backgroundColor = '#f8f8f8'
          $startDrawing.style.color = 'black'
        })

        // 清除围栏
        $clearFences.addEventListener('click', () => {
          geoFences.forEach((fence) => map.removeOverlay(fence.polygon))
          geoFences = []
        })

        // 点击添加围栏点
        map.addEventListener('click', (e) => {
          if (!isDrawing) return
          currentFence.points.push(e.point)
          updateDrawingPolygon()

          // 在点击位置添加标记
          const marker = new BMap.Marker(e.point)
          map.addOverlay(marker)
          setTimeout(() => map.removeOverlay(marker), 1000)
        })
      }

      // 更新绘制中的多边形
      function updateDrawingPolygon() {
        if (currentFence.polygon) map.removeOverlay(currentFence.polygon)

        // 绘制当前多边形（不闭合）
        currentFence.polygon = new BMap.Polygon(currentFence.points, {
          strokeColor: '#33cc33',
          strokeWeight: 2,
          strokeOpacity: 0.8,
          fillColor: '#66ff66',
          fillOpacity: 0.3,
        })
        map.addOverlay(currentFence.polygon)
      }

      // 完成围栏绘制
      function finalizeFence() {
        if (currentFence.points.length < 3) {
          alert('围栏至少需要3个点')
          return
        }

        // 闭合多边形
        const points = [...currentFence.points, currentFence.points[0]]
        currentFence.polygon.setPath(points)
        currentFence.points = points

        geoFences.push(currentFence)
        isDrawing = false
        currentFence = null

        // 添加围栏名称标签
        const center = getPolygonCenter(points)
      }

      // 计算多边形中心点
      function getPolygonCenter(points) {
        let x = 0,
          y = 0
        points.forEach((point) => {
          x += point.lng
          y += point.lat
        })
        return new BMap.Point(x / points.length, y / points.length)
      }

      // 取消绘制
      function cancelDrawing() {
        if (!isDrawing) return
        if (currentFence.polygon) map.removeOverlay(currentFence.polygon)
        isDrawing = false
        currentFence = null
        $startDrawing.style.backgroundColor = '#f8f8f8'
        $startDrawing.style.color = 'black'
      }

      // 检查地理围栏
      function checkGeoFences(vehiclePoint) {
        if (!vehiclePoint || geoFences.length === 0) return

        let isInAnyFence = false
        let violatingFence = null

        geoFences.forEach((fence) => {
          const isInside = BMapLib.GeoUtils.isPointInPolygon(
            vehiclePoint,
            fence.polygon
          )

          if (isInside) {
            isInAnyFence = true
            violatingFence = fence
          }
        })

        // 更新状态显示
        if (!isInAnyFence) {
          $statusIndicator.className = 'status-indicator status-alarm'
          $statusText.textContent = '越界!'
          triggerAlarm(vehiclePoint)
        } else {
          $statusIndicator.className = 'status-indicator status-ok'
          $statusText.textContent = '正常'
        }

        // 将车辆位置转换为WGS84坐标上传检查
        convertor.translate(
          [vehiclePoint],
          config.convertOptions.to,
          config.convertOptions.from,
          (result) => {
            if (
              result.status === 0 &&
              result.points &&
              result.points.length > 0
            ) {
              const wgs84Point = result.points[0]
              if (!isInAnyFence) {
                checkFenceViolation(
                  violatingFence.id,
                  wgs84Point.lng,
                  wgs84Point.lat,
                  isInside
                )
              }
            }
          }
        )
      }

      // 触发报警
      function triggerAlarm(vehiclePoint) {
        // 播放报警声音
        alarmSound.currentTime = 0
        alarmSound.play().catch((e) => console.log('音频播放被阻止:', e))

        // 显示报警提示
        $alarm.style.display = 'block'
        $alarmDetails.innerHTML = `
          <div>时间: ${new Date().toLocaleTimeString()}</div>
          <div>车辆已离开围栏区域!</div>
        `

        functions.overFence()
      }

      // 检查围栏违规
      function checkFenceViolation(fenceId, lng, lat, isInside) {
        const checkData = {
          fenceId: fenceId,
          vehicleLocation: { lng, lat },
          isInside: isInside,
          checkTime: new Date().toISOString(),
        }
      }

      // 设置模拟控制
      function setupSimulationControls() {
        $startSimulation.addEventListener('click', startSimulation)
        $stopSimulation.addEventListener('click', stopSimulation)
      }

      // 开始模拟
      function startSimulation() {
        if (isSimulating) return

        isSimulating = true
        $startSimulation.style.backgroundColor = '#4CAF50'
        $startSimulation.style.color = 'white'

        // 初始化当前坐标（如果已有坐标则使用，否则使用配置起点）
        let currentLng =
          currentVehiclePosition?.lng || config.simulation.points[0].lng
        let currentLat =
          currentVehiclePosition?.lat || config.simulation.points[0].lat

        simulationInterval = setInterval(() => {
          // 每次增加0.001
          currentLng += config.simulation.speed
          currentLat += config.simulation.speed

          // 更新车辆位置
          updateVehiclePosition(currentLng, currentLat)

          // 更新当前车辆位置记录
          currentVehiclePosition = { lng: currentLng, lat: currentLat }
        }, config.simulation.interval)
      }

      // 停止模拟
      function stopSimulation() {
        if (!isSimulating) return

        isSimulating = false
        clearInterval(simulationInterval)
        $startSimulation.style.backgroundColor = '#f8f8f8'
        $startSimulation.style.color = 'black'
      }

      // 设置消息监听
      function setupMessageListener() {
        window.addEventListener('message', function (event) {
          // 初始化端口通信
          if (
            event.data === '__init_port__' &&
            event.ports &&
            event.ports.length > 0
          ) {
            messagePort = event.ports[0]
            messagePort.onmessage = handlePortMessage
            return
          }

          // 直接消息处理
          handleAppMessage(event.data)
        })
      }

      // 处理端口消息
      function handlePortMessage(event) {
        handleAppMessage(event.data)
      }

      // 处理应用消息
      function handleAppMessage(data) {
        let locationData

        // 解析消息数据
        if (typeof data === 'string') {
          try {
            locationData = JSON.parse(data)
          } catch (e) {
            console.error('消息解析失败:', e)
            return
          }
        } else if (typeof data === 'object') {
          locationData = data
        } else {
          console.error('无效的消息格式')
          return
        }

        // 验证位置数据
        if (locationData && locationData.longitude && locationData.latitude) {
          updateVehiclePosition(
            parseFloat(locationData.longitude),
            parseFloat(locationData.latitude)
          )
        }
      }

      // 页面加载完成后初始化
      window.onload = init

      // 页面卸载时清理
      window.onbeforeunload = function () {
        stopSimulation()
      }
    </script>
  </body>
</html>
